import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:hkzf/model/user.dart';
import 'package:hkzf/utils/common_toast.dart';
import 'package:hkzf/utils/store.dart';
import 'package:provider/provider.dart';

import '../config.dart';

class DioHttp {
  Dio _client;
  BuildContext context;
  static DioHttp of(BuildContext context) {
    return DioHttp._internal(context);
  }

  DioHttp._internal(BuildContext context) {
    if (_client == null || context != this.context) {
      // if (_client == null && context != null) {
      this.context = context;
      var options = BaseOptions(
          baseUrl: Config.BaseUrl,
          connectTimeout: 1000 * 10,
          receiveTimeout: 1000 * 3,
          extra: {
            'context': context,
          });
      this._client = Dio(options);
    }
  }

  static Future<String> getToken() async {
    var store = await Store.getInstance();
    String token = await store.getString(StoreKeys.token);
    return 'Bearer ' + token;
  }

  Future<Map<String, dynamic>> get(
    String path, {
    Map<String, dynamic> params,
    String token,
    Function success,
    Function error,
  }) async {
    var token = await getToken();
    var options = Options(headers: {
      'Authorization': token ??
          'Bearer ' + context.select((UserInfo userInfo) => userInfo.token)
    });
    try {
      //404
      Response res =
          await _client.get(path, queryParameters: params, options: options);
      if (res != null) {
        var resString = json.decode(res.toString());
        if (resString['code'] != 200) {
          CommonToast.showToast(resString['message']);
        }
        return resString;
      }
    } on DioError catch (e) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx and is also not 304.
      if (e != null && e.response != null) {
        switch (e.response.statusCode) {
          case 401:
            {
              CommonToast.showToast('登录信息超时，请重新登录');
              Navigator.of(context).pushNamed('/login');
              break;
            }
          default:
            {
              CommonToast.showToast(e.response.data['message']);
            }
        }
      } else {
        // Something happened in setting up or sending the request that triggered an Error
        switch (e.type) {
          case DioErrorType.CONNECT_TIMEOUT:
            {
              CommonToast.showToast('连接超时，请检查您的网络连接！');
              break;
            }
          case DioErrorType.CANCEL:
            {
              CommonToast.showToast('请求已取消！');
              break;
            }
          case DioErrorType.RECEIVE_TIMEOUT:
            {
              CommonToast.showToast('响应超时，请检查您的网络连接！');
              break;
            }
          case DioErrorType.SEND_TIMEOUT:
            {
              CommonToast.showToast('请求超时，请检查您的网络连接！');
              break;
            }
          default:
            {
              CommonToast.showToast('未知错误！');
              break;
            }
        }
      }
    }
  }

  Future<Map<String, dynamic>> post(
    String path, {
    Map<String, dynamic> params,
    String token,
  }) async {
    var token = await getToken();
    var options = Options(headers: {
      'Authorization': token ?? 'Bearer ' + context.read<UserInfo>().token
    });
    try {
      //404
      Response res = await _client.post(path, data: params, options: options);
      if (res != null) {
        var resString = json.decode(res.toString());
        if (resString['code'] != 200) {
          CommonToast.showToast(resString['message']);
        }
        return resString;
      }
    } on DioError catch (e) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx and is also not 304.
      if (e != null && e.response != null) {
        CommonToast.showToast(e.response.data['message']);
      } else {
        // Something happened in setting up or sending the request that triggered an Error
        switch (e.type) {
          case DioErrorType.CONNECT_TIMEOUT:
            {
              CommonToast.showToast('连接超时，请检查您的网络连接！');
              break;
            }
          case DioErrorType.CANCEL:
            {
              CommonToast.showToast('请求已取消！');
              break;
            }
          case DioErrorType.RECEIVE_TIMEOUT:
            {
              CommonToast.showToast('响应超时，请检查您的网络连接！');
              break;
            }
          case DioErrorType.SEND_TIMEOUT:
            {
              CommonToast.showToast('请求超时，请检查您的网络连接！');
              break;
            }
          default:
            {
              CommonToast.showToast('未知错误！');
              break;
            }
        }
      }
    }
  }

  Future<Map<String, dynamic>> postData(String path,
      {FormData params, String token}) async {
    var token = await getToken();

    var options = Options(contentType: 'multipart/form-data', headers: {
      'Authorization': token ?? 'Bearer ' + context.read<UserInfo>().token
    });
    try {
      //404
      Response res = await _client.post(path, data: params, options: options);
      if (res != null) {
        var resString = json.decode(res.toString());
        if (resString['code'] != 200) {
          CommonToast.showToast(resString['message']);
        }
        return resString;
      }
    } on DioError catch (e) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx and is also not 304.
      if (e != null && e.response != null) {
        switch (e.response.statusCode) {
          case 401:
            {
              CommonToast.showToast('登录信息超时，请重新登录');
              Navigator.of(context).pushNamed('/login');
              break;
            }
          default:
            {
              CommonToast.showToast(e.response.data['message']);
            }
        }
      } else {
        // Something happened in setting up or sending the request that triggered an Error
        switch (e.type) {
          case DioErrorType.CONNECT_TIMEOUT:
            {
              CommonToast.showToast('连接超时，请检查您的网络连接！');
              break;
            }
          case DioErrorType.CANCEL:
            {
              CommonToast.showToast('请求已取消！');
              break;
            }
          case DioErrorType.RECEIVE_TIMEOUT:
            {
              CommonToast.showToast('响应超时，请检查您的网络连接！');
              break;
            }
          case DioErrorType.SEND_TIMEOUT:
            {
              CommonToast.showToast('请求超时，请检查您的网络连接！');
              break;
            }
          default:
            {
              CommonToast.showToast('未知错误！');
              break;
            }
        }
      }
    }
  }
}
